#include "ili9320.h"

#include "ili9320_registers.h"

static void ili9320_write_reg(ili9320_desc_t *pili9320, uint8_t reg, uint16_t val) {
  pili9320->write_cmd(reg);
  pili9320->write_data(val);
}

static uint16_t ili9320_read_reg(ili9320_desc_t *pili9320, uint8_t reg) {
  pili9320->write_cmd(reg);
  return pili9320->read_data();
}

static void ili9320_write_data(ili9320_desc_t *pili9320, uint16_t *pdata, uint32_t length) {
  pili9320->write_cmd(LCD_REG_34);
  for (uint32_t i = 0; i < length; i++) {
    pili9320->write_block(pdata, length);
  }
}
static void ili9320_read_data(ili9320_desc_t *pili9320, uint8_t reg, uint16_t val) {}

int ili9320_init(ili9320_desc_t *pili9320) {
  uint32_t lcd_id = 0;

  lcd_id = ili9320_read_reg(pili9320, LCD_REG_0);

  debug_info("lcd id:%04x\r\n", lcd_id);

  // lcd 9320
  /* Start Initial Sequence ------------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_229, 0x8000);
  ili9320_write_reg(pili9320, LCD_REG_0, 0x0001);  /* Start internal OSC. */
  ili9320_write_reg(pili9320, LCD_REG_1, 0x0100);  /* set SS and SM bit */
  ili9320_write_reg(pili9320, LCD_REG_2, 0x0700);  /* set 1 line inversion */
  ili9320_write_reg(pili9320, LCD_REG_3, 0x1030);  /* set GRAM write direction and BGR=1. */
  ili9320_write_reg(pili9320, LCD_REG_4, 0x0000);  /* Resize register */
  ili9320_write_reg(pili9320, LCD_REG_8, 0x0202);  /* set the back porch and front porch */
  ili9320_write_reg(pili9320, LCD_REG_9, 0x0000);  /* set non-display area refresh cycle ISC[3:0] */
  ili9320_write_reg(pili9320, LCD_REG_10, 0x0000); /* FMARK function */
  ili9320_write_reg(pili9320, LCD_REG_12, 0x0000); /* RGB interface setting */
  ili9320_write_reg(pili9320, LCD_REG_13, 0x0000); /* Frame marker Position */
  ili9320_write_reg(pili9320, LCD_REG_15, 0x0000); /* RGB interface polarity */

  /* Power On sequence -----------------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_16, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
  ili9320_write_reg(pili9320, LCD_REG_17, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */
  ili9320_write_reg(pili9320, LCD_REG_18, 0x0000); /* VREG1OUT voltage */
  ili9320_write_reg(pili9320, LCD_REG_19, 0x0000); /* VDV[4:0] for VCOM amplitude */
  bsp_os_delay_ms(200);                            /* Dis-charge capacitor power voltage (200ms) */
  ili9320_write_reg(pili9320, LCD_REG_16, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
  ili9320_write_reg(pili9320, LCD_REG_17, 0x0137); /* DC1[2:0], DC0[2:0], VC[2:0] */
  bsp_os_delay_ms(50);                             /* Delay 50 ms */

  ili9320_write_reg(pili9320, LCD_REG_18, 0x0139); /* VREG1OUT voltage */
  bsp_os_delay_ms(50);                             /* Delay 50 ms */
  ili9320_write_reg(pili9320, LCD_REG_19, 0x1d00); /* VDV[4:0] for VCOM amplitude */
  ili9320_write_reg(pili9320, LCD_REG_41, 0x0013); /* VCM[4:0] for VCOMH */
  bsp_os_delay_ms(50);                             /* Delay 50 ms */
  ili9320_write_reg(pili9320, LCD_REG_32, 0x0000); /* GRAM horizontal Address */
  ili9320_write_reg(pili9320, LCD_REG_33, 0x0000); /* GRAM Vertical Address */

  /* Adjust the Gamma Curve ------------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_48, 0x0006);
  ili9320_write_reg(pili9320, LCD_REG_49, 0x0101);
  ili9320_write_reg(pili9320, LCD_REG_50, 0x0003);
  ili9320_write_reg(pili9320, LCD_REG_53, 0x0106);
  ili9320_write_reg(pili9320, LCD_REG_54, 0x0b02);
  ili9320_write_reg(pili9320, LCD_REG_55, 0x0302);
  ili9320_write_reg(pili9320, LCD_REG_56, 0x0707);
  ili9320_write_reg(pili9320, LCD_REG_57, 0x0007);
  ili9320_write_reg(pili9320, LCD_REG_60, 0x0600);
  ili9320_write_reg(pili9320, LCD_REG_61, 0x020b);

  /* Set GRAM area ---------------------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_80, 0x0000);  /* Horizontal GRAM Start Address */
  ili9320_write_reg(pili9320, LCD_REG_81, 0x00EF);  /* Horizontal GRAM End Address */
  ili9320_write_reg(pili9320, LCD_REG_82, 0x0000);  /* Vertical GRAM Start Address */
  ili9320_write_reg(pili9320, LCD_REG_83, 0x013F);  /* Vertical GRAM End Address */
  ili9320_write_reg(pili9320, LCD_REG_96, 0x2700);  /* Gate Scan Line */
  ili9320_write_reg(pili9320, LCD_REG_97, 0x0001);  /* NDL,VLE, REV */
  ili9320_write_reg(pili9320, LCD_REG_106, 0x0000); /* set scrolling line */

  /* Partial Display Control -----------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_128, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_129, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_130, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_131, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_132, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_133, 0x0000);

  /* Panel Control ---------------------------------------------------------*/
  ili9320_write_reg(pili9320, LCD_REG_144, 0x0010);
  ili9320_write_reg(pili9320, LCD_REG_146, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_147, 0x0003);
  ili9320_write_reg(pili9320, LCD_REG_149, 0x0110);
  ili9320_write_reg(pili9320, LCD_REG_151, 0x0000);
  ili9320_write_reg(pili9320, LCD_REG_152, 0x0000);

  /* Set GRAM write direction and BGR = 1 */
  /* I/D=01 (Horizontal : increment, Vertical : decrement) */
  /* AM=1 (address is updated in vertical writing direction) */
  ili9320_write_reg(pili9320, LCD_REG_3, 0x1018);

  ili9320_write_reg(pili9320, LCD_REG_7, 0x0173); /* 262K color and display ON */

  return 0;
}

void ili9320_display_on(ili9320_desc_t *pili9320) { ili9320_write_reg(pili9320, LCD_REG_7, 0x0173); }

void ili9320_display_off(ili9320_desc_t *pili9320) { ili9320_write_reg(pili9320, LCD_REG_7, 0x0000); }

void ili9320_test() {
  extern ili9320_desc_t m_ili9320;
  ili9320_init(&m_ili9320);
  uint16_t data[64];
  memset(data, 0x55, 128);

  ili9320_write_reg(&m_ili9320, LCD_REG_32, 50);
  ili9320_write_reg(&m_ili9320, LCD_REG_33, 50);
  ili9320_write_data(&m_ili9320, data, 64);
}